Skip to content

fix(location): use native cached location fallback - #339

Draft
Alexander-Noah wants to merge 1 commit into
1024XEngineer:mainfrom
Alexander-Noah:codex/location-native-fallback
Draft

fix(location): use native cached location fallback#339
Alexander-Noah wants to merge 1 commit into
1024XEngineer:mainfrom
Alexander-Noah:codex/location-native-fallback

Conversation

@Alexander-Noah

@Alexander-Noah Alexander-Noah commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

关联 Issue 与前置工作

Closes #338

本 PR 为 Android 增加 native last-known location 兜底。当 Expo 缓存或实时定位不可用时,语音握手和 geofence 仍可使用符合时效与精度要求的系统缓存位置;定位不可用或响应过慢时,不阻塞语音连接。

当前提交:

6c43662 fix(location): use native cached location fallback

当前分支:

codex/location-native-fallback

背景与目标

Android 系统可能已经保存了可用的 last-known location,但 Expo getCurrentPositionAsync 仍可能返回 ERR_CURRENT_LOCATION_IS_UNAVAILABLE。此前业务无法继续读取系统缓存位置,导致语音握手和 geofence 初始化获得 null;实时定位响应较慢时,还会延迟语音连接。

本 PR 目标:

  • 增加 Android native cached location 数据源;
  • 将 native fallback 接入语音和 geofence 定位流程;
  • 只接受 60 秒内、精度不超过 200 米的有效缓存;
  • 将语音启动阶段的定位等待上限缩短到 500ms;
  • 避免权限或定位 API 异常形成未捕获的 Promise rejection;
  • 提供 development build 真机定位探针。

完整流程

位置获取流程:

业务请求位置
  -> 读取 Expo 短期缓存
  -> Expo 缓存不可用时读取 Android native last-known location
  -> 校验坐标、观测时间和精度
  -> native 缓存合格时立即返回,并异步刷新 Expo current position
  -> native 缓存不可用时等待 Expo current position
  -> 所有来源均不可用时安全返回 null

语音启动流程:

定位在 500ms 内返回
  -> 将位置附加到语音握手

定位超过 500ms 或失败
  -> 本次 location sample 使用 null
  -> 语音连接继续启动

主要改动

Android native location

新增 TimeflowLocation native module:

  • networkpassivegpsfused provider 读取 last-known location;
  • provider 即使处于禁用状态,也继续尝试读取系统保留的缓存;
  • 单个 provider 不存在或读取异常时安全跳过;
  • 只接受坐标合法、观测时间有效、缓存年龄不超过 60 秒且精度不超过 200 米的样本;
  • 多个样本优先选择观测时间更新的位置,时间相同时选择精度更高的位置;
  • 缺失时间不会被替换为当前时间,缺失或非法精度不会被替换为 0 米;
  • 生产日志只记录 provider、缓存年龄和精度,不输出经纬度。

涉及文件:

  • LocationModule.kt
  • LocationSnapshotReader.kt
  • LocationSnapshotSelector.kt
  • AlarmPackage.kt
  • Android module manifest

JavaScript native fallback

新增 NativeLocationFallback.ts

  • 调用 TimeflowLocation native module;
  • 将原生 payload 映射为统一的 LocationSample
  • 原生模块不存在、调用失败、字段缺失或坐标非法时返回 null
  • 不在生产日志中输出精确经纬度。

Expo location provider

更新 ExpoLocationProvider.ts

  • 优先使用 Expo 短期缓存;
  • Expo 缓存不可用时读取 native cached location;
  • native 缓存命中后立即返回,并在后台刷新 Expo current position;
  • native 缓存不可用时回退到 Expo 实时定位;
  • 定位失败时返回 null,不主动弹出权限请求。

Geofence monitor

更新 ExpoLocationMonitor.ts

  • Expo current position 失败时回退 native cached location;
  • native 缓存命中后更新 lastSample
  • 前台定位权限未授予时跳过采样;
  • 后台权限状态读取失败时跳过区域同步;
  • 在异步调用边界处理拒绝,避免未捕获异常。

Assistant conversation

更新:

  • AssistantConversationService.ts
  • AssistantContinuousConversationService.ts

将语音启动阶段的定位等待上限从 2000ms 调整为 500ms。定位超时只省略本次位置,不阻塞语音连接。

Development build

增加:

  • expo-dev-client
  • timeflow URL scheme;
  • development startup location probe;
  • Android native module 真机验证入口。

精确坐标仅允许由受 __DEV__EXPO_PUBLIC_LOCATION_PROBE_ON_START 双重控制的开发探针输出。

验收行为

场景 预期行为
Expo 短期缓存可用 直接返回 Expo 缓存,并异步刷新当前位置
Expo 缓存不可用,native 缓存合格 立即返回 native 缓存,并异步刷新当前位置
native provider 当前禁用但仍有缓存 继续尝试读取并校验该缓存
native 缓存超过 60 秒 拒绝使用,继续尝试 Expo 实时定位
native 缓存精度超过 200 米 拒绝使用,继续尝试 Expo 实时定位
native 缓存缺失时间或精度 拒绝使用,不伪造默认值
定位超过 500ms 语音连接继续启动,本次不附加位置
Expo current position 失败 geofence 尝试 native fallback
所有定位来源不可用 安全返回 null
后台定位权限不可用 跳过 geofence 同步,不产生未捕获异常
生产环境命中 native 缓存 日志不包含精确经纬度

测试覆盖

新增或更新:

  • LocationSnapshotReaderTest.java
  • LocationSnapshotSelectorTest.java
  • nativeLocationFallback.test.ts
  • expoLocationProvider.test.ts
  • expoLocationMonitor.test.ts
  • AssistantConversationService.test.ts
  • AssistantContinuousConversationService.test.ts

覆盖内容:

  • provider 禁用时仍读取系统缓存;
  • provider 读取异常时安全跳过;
  • 多 provider 最新时间和同时间精度选择;
  • 60 秒缓存时效与 200 米精度边界;
  • 过期、未来、缺失时间和非法精度过滤;
  • native payload 映射、空结果、异常和非法坐标;
  • Expo 缓存、native fallback 与实时定位 fallback;
  • geofence current position 失败后的 native fallback;
  • 慢定位不阻塞语音连接;
  • native fallback 命中时不输出精确坐标。

当前验证结果

本地验证:

  • npm run lint
  • npm run typecheck
  • Vitest:9 files,87 tests passed
  • Jest:67 suites,631 tests passed
  • ./gradlew :timeflow-alarm:testDebugUnitTest:BUILD SUCCESSFUL
  • git diff --check
  • 远端分支 SHA 与本地提交一致

GitHub CI:

  • Backend (lint, types, tests)
  • Backend (migrations)
  • Frontend (lint, types, build)
  • codecov/patch

范围与非目标

本 PR 不处理:

  • 完整后台定位授权流程;
  • 强制申请 ACCESS_BACKGROUND_LOCATION
  • geofence enter/exit 状态机调整;
  • 保证每次获得实时 GPS 坐标;
  • iOS native cached location;
  • 通用定位缓存策略重构;
  • GitHub Actions Node.js 20 弃用警告;
  • docker-compose.yml 配置调整。

风险与兼容性

  • last-known location 仍是缓存数据,但本 PR 将可用范围限制为 60 秒内且精度不超过 200 米;
  • 不同 Android 设备可用的 provider 可能不同,缺失或不可访问的 provider 会被跳过;
  • 新增 native module 后需要重新构建 development build,Expo Go 不包含该模块;
  • geofence 后台运行仍受 Android 后台定位权限约束;
  • 生产日志不再输出经纬度,真机坐标诊断需要显式启用开发探针。

Review Checklist

  • PR 已通过 Closes #338 关联 Issue。
  • Diff 与 Issue 范围一致。
  • docker-compose.yml 未包含在 PR 中。
  • 已处理禁用 provider 的 review comment。
  • 已增加 native 缓存时效与精度门槛。
  • 已移除生产路径中的精确坐标日志。
  • TypeScript、ESLint、前端测试和 Android native 测试通过。
  • GitHub CI 和 Codecov 通过。
  • Android development build 已验证 native cached location。

@Alexander-Noah
Alexander-Noah force-pushed the codex/location-native-fallback branch from 4d8e99f to 922b2b7 Compare August 21, 2026 03:22
@Alexander-Noah

Copy link
Copy Markdown
Contributor Author

@fennoai /review

@fennoai

fennoai Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Review Complete

  • Reviewed the fixed range 2c1d7f4ed983bd37001869ac27811efb56effeb5...922b2b709f5062efbe8b799a1086618a388f511f across all 21 changed files.
  • Submitted one non-blocking PR review with a [P1] finding: docker-compose.yml now requires an untracked backend/.env, while the documented setup creates the repository-root .env; fresh checkouts therefore fail before the API starts.
  • Location fallback, native payload validation, geofence fallback, and 500 ms voice startup timeout were otherwise internally consistent on inspection.
  • Focused Jest and TypeScript checks were unavailable because local node_modules executables are absent/non-executable; no files were modified.

@fennoai fennoai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the Android native cached-location module, JavaScript fallback/provider and geofence integration, assistant location timeout, and development-build configuration. The location fallback contracts and timeout behavior are coherent, but the new Compose configuration introduces a fresh-checkout startup regression described in the inline finding below. Focused Jest and TypeScript verification could not run in this workspace because the local node_modules executables are absent/non-executable; the review otherwise used the fixed PR diff and affected callers.

Comment thread docker-compose.yml Outdated
@Alexander-Noah
Alexander-Noah force-pushed the codex/location-native-fallback branch from 922b2b7 to 0dee55e Compare August 21, 2026 03:33
@Alexander-Noah
Alexander-Noah marked this pull request as ready for review August 21, 2026 03:39
@codecov

codecov Bot commented Aug 21, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.43750% with 1 line in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
.../infrastructure/location/NativeLocationFallback.ts 96.66% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@fennoai fennoai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已审查 Android native last-known location、JS bridge/probe、Expo provider、geofence monitor 和两条语音启动超时链路。整体 fallback 与异常收敛契约一致,但 native provider 读取前的 enabled 检查会漏掉系统仍保留的缓存位置。

验证方面,已核对固定范围 2c1d7f4ed983bd37001869ac27811efb56effeb5...0dee55e98c75eaf72b9c6b61e675863d3ef13ba8 的全部 20 个文件;本地 checkout 未安装 Jest 包,因此无法复跑前端测试(npm 首先报可执行权限错误,直接通过 Node 调用时确认 node_modules/jest 不存在)。

@Alexander-Noah
Alexander-Noah force-pushed the codex/location-native-fallback branch 4 times, most recently from e841ae8 to 5fe6618 Compare August 21, 2026 07:51
@Alexander-Noah

Copy link
Copy Markdown
Contributor Author

已补充修复并推送到提交 \5fe6618\:

  • Android native last-known location 仅接受 60 秒内、精度不超过 200 米且时间与精度有效的缓存;
  • 不再把缺失时间伪装为当前时间,也不再把缺失或非法精度转换为 0 米;
  • 已移除生产路径中的精确经纬度日志,仅保留 provider、缓存年龄和精度;
  • 已新增过期、未来时间、缺失时间、非法精度、精度上限及日志隐私回归测试。

验证结果:Vitest 87/87、Jest 626/626、Android :timeflow-alarm:testDebugUnitTest\、TypeScript、ESLint、Codecov 和全部 PR CI 均通过。现有 review thread 均已解决。

@Alexander-Noah
Alexander-Noah force-pushed the codex/location-native-fallback branch from 5fe6618 to 6c43662 Compare August 21, 2026 08:08
@Alexander-Noah
Alexander-Noah requested review from LUPENGHAN and removed request for LUPENGHAN August 21, 2026 08:11
@Alexander-Noah
Alexander-Noah marked this pull request as draft August 21, 2026 10:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Android 定位采样在实时定位不可用时缺少可用兜底

1 participant